package com.summer.filesync.manager.service;

import com.summer.filesync.database.dao.FileMetadataDAO;
import com.summer.filesync.model.FileMetadata;
import com.summer.filesync.model.manager.FileSearchCriteria;
import com.summer.filesync.util.Logger;
import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/** 文件搜索服务 提供高级文件搜索功能 */
public class FileSearchService {
  private static final Logger logger = Logger.getLogger(FileSearchService.class);

  private final FileMetadataDAO fileMetadataDAO;
  private final ExecutorService searchExecutor;
  private final Map<String, List<FileMetadata>> searchIndexCache;

  public FileSearchService(FileMetadataDAO fileMetadataDAO) {
    this.fileMetadataDAO = fileMetadataDAO;
    this.searchExecutor = Executors.newFixedThreadPool(4);
    this.searchIndexCache = new ConcurrentHashMap<>();
  }

  /** 根据条件搜索文件 */
  public CompletableFuture<List<FileMetadata>> searchFiles(FileSearchCriteria criteria) {
    return CompletableFuture.supplyAsync(
        () -> {
          logger.info("开始搜索文件，条件: " + criteria.getName());

          try {
            List<FileMetadata> results = new ArrayList<>();

            // 如果有搜索路径，使用文件系统搜索
            if (criteria.getSearchPaths() != null && !criteria.getSearchPaths().isEmpty()) {
              for (String searchPath : criteria.getSearchPaths()) {
                results.addAll(searchInFileSystem(criteria, searchPath));
              }
            } else {
              // 使用数据库搜索
              results.addAll(searchInDatabase(criteria));
            }

            // 应用额外过滤器
            results = applyFilters(results, criteria);

            // 排序结果
            results = sortResults(results, criteria);

            // 限制结果数量
            if (criteria.getMaxResults() > 0 && results.size() > criteria.getMaxResults()) {
              results = results.subList(0, criteria.getMaxResults());
            }

            logger.info("搜索完成，找到 " + results.size() + " 个文件");
            return results;

          } catch (Exception e) {
            logger.error("文件搜索失败", e);
            return new ArrayList<>();
          }
        },
        searchExecutor);
  }

  /** 快速文件名搜索 */
  public CompletableFuture<List<FileMetadata>> quickSearch(String fileName) {
    FileSearchCriteria criteria = new FileSearchCriteria();
    criteria.setName(fileName);
    criteria.setMaxResults(50);
    criteria.setCaseSensitive(false);

    return searchFiles(criteria);
  }

  /** 内容搜索 */
  public CompletableFuture<List<FileMetadata>> searchByContent(
      String content, List<String> searchPaths) {
    return CompletableFuture.supplyAsync(
        () -> {
          logger.info("开始内容搜索: " + content);

          List<FileMetadata> results = new ArrayList<>();
          Pattern contentPattern =
              Pattern.compile(Pattern.quote(content), Pattern.CASE_INSENSITIVE);

          try {
            for (String searchPath : searchPaths) {
              Files.walkFileTree(
                  Paths.get(searchPath),
                  new SimpleFileVisitor<Path>() {
                    @Override
                    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                        throws IOException {
                      if (isTextFile(file) && attrs.size() < 10 * 1024 * 1024) { // 限制10MB以下文件
                        try {
                          String fileContent = Files.readString(file);
                          if (contentPattern.matcher(fileContent).find()) {
                            FileMetadata metadata = createFileMetadata(file, attrs);
                            results.add(metadata);
                          }
                        } catch (Exception e) {
                          // 忽略读取失败的文件
                        }
                      }
                      return FileVisitResult.CONTINUE;
                    }

                    @Override
                    public FileVisitResult visitFileFailed(Path file, IOException exc)
                        throws IOException {
                      return FileVisitResult.CONTINUE;
                    }
                  });
            }
          } catch (Exception e) {
            logger.error("内容搜索失败", e);
          }

          logger.info("内容搜索完成，找到 " + results.size() + " 个文件");
          return results;
        },
        searchExecutor);
  }

  /** 重复文件搜索 */
  public CompletableFuture<Map<String, List<FileMetadata>>> findDuplicateFiles(
      List<String> searchPaths) {
    return CompletableFuture.supplyAsync(
        () -> {
          logger.info("开始搜索重复文件");

          Map<Long, List<FileMetadata>> sizeGroups = new HashMap<>();
          Map<String, List<FileMetadata>> duplicates = new HashMap<>();

          try {
            // 按大小分组
            for (String searchPath : searchPaths) {
              Files.walkFileTree(
                  Paths.get(searchPath),
                  new SimpleFileVisitor<Path>() {
                    @Override
                    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                        throws IOException {
                      if (attrs.isRegularFile() && attrs.size() > 0) {
                        FileMetadata metadata = createFileMetadata(file, attrs);
                        sizeGroups
                            .computeIfAbsent(attrs.size(), k -> new ArrayList<>())
                            .add(metadata);
                      }
                      return FileVisitResult.CONTINUE;
                    }
                  });
            }

            // 对相同大小的文件计算哈希值
            for (Map.Entry<Long, List<FileMetadata>> entry : sizeGroups.entrySet()) {
              if (entry.getValue().size() > 1) {
                Map<String, List<FileMetadata>> hashGroups =
                    entry.getValue().stream()
                        .collect(Collectors.groupingBy(this::calculateFileHash));

                for (Map.Entry<String, List<FileMetadata>> hashEntry : hashGroups.entrySet()) {
                  if (hashEntry.getValue().size() > 1) {
                    duplicates.put(hashEntry.getKey(), hashEntry.getValue());
                  }
                }
              }
            }

          } catch (Exception e) {
            logger.error("搜索重复文件失败", e);
          }

          logger.info("重复文件搜索完成，找到 " + duplicates.size() + " 组重复文件");
          return duplicates;
        },
        searchExecutor);
  }

  /** 建立搜索索引 */
  public CompletableFuture<Void> buildSearchIndex(List<String> indexPaths) {
    return CompletableFuture.runAsync(
        () -> {
          logger.info("开始建立搜索索引");

          for (String indexPath : indexPaths) {
            try {
              List<FileMetadata> indexFiles = new ArrayList<>();

              Files.walkFileTree(
                  Paths.get(indexPath),
                  new SimpleFileVisitor<Path>() {
                    @Override
                    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                        throws IOException {
                      if (attrs.isRegularFile()) {
                        FileMetadata metadata = createFileMetadata(file, attrs);
                        indexFiles.add(metadata);
                      }
                      return FileVisitResult.CONTINUE;
                    }
                  });

              searchIndexCache.put(indexPath, indexFiles);
              logger.debug("为路径建立索引: " + indexPath + "，文件数: " + indexFiles.size());

            } catch (Exception e) {
              logger.error("建立索引失败: " + indexPath, e);
            }
          }

          logger.info("搜索索引建立完成");
        },
        searchExecutor);
  }

  /** 关闭搜索服务 */
  public void shutdown() {
    logger.info("文件搜索服务正在关闭...");
    searchExecutor.shutdown();
    try {
      if (!searchExecutor.awaitTermination(10, TimeUnit.SECONDS)) {
        searchExecutor.shutdownNow();
      }
    } catch (InterruptedException e) {
      searchExecutor.shutdownNow();
      Thread.currentThread().interrupt();
    }
    searchIndexCache.clear();
  }

  /** 在文件系统中搜索 */
  private List<FileMetadata> searchInFileSystem(FileSearchCriteria criteria, String searchPath) {
    List<FileMetadata> results = new ArrayList<>();

    try {
      // 使用索引缓存（如果可用）
      List<FileMetadata> indexedFiles = searchIndexCache.get(searchPath);
      if (indexedFiles != null) {
        results.addAll(
            indexedFiles.stream()
                .filter(file -> matchesCriteria(file, criteria))
                .collect(Collectors.toList()));
      } else {
        // 实时文件系统搜索
        Files.walkFileTree(
            Paths.get(searchPath),
            new SimpleFileVisitor<Path>() {
              @Override
              public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                  throws IOException {
                FileMetadata metadata = createFileMetadata(file, attrs);
                if (matchesCriteria(metadata, criteria)) {
                  results.add(metadata);
                }
                return FileVisitResult.CONTINUE;
              }

              @Override
              public FileVisitResult visitFileFailed(Path file, IOException exc)
                  throws IOException {
                return FileVisitResult.CONTINUE;
              }
            });
      }
    } catch (Exception e) {
      logger.error("文件系统搜索失败: " + searchPath, e);
    }

    return results;
  }

  /** 在数据库中搜索 */
  private List<FileMetadata> searchInDatabase(FileSearchCriteria criteria) {
    // 简化实现，实际应使用数据库查询
    return new ArrayList<>();
  }

  /** 应用过滤器 */
  private List<FileMetadata> applyFilters(List<FileMetadata> files, FileSearchCriteria criteria) {
    return files.stream()
        .filter(file -> matchesCriteria(file, criteria))
        .collect(Collectors.toList());
  }

  /** 检查文件是否匹配条件 */
  private boolean matchesCriteria(FileMetadata file, FileSearchCriteria criteria) {
    // 文件名匹配
    if (criteria.getName() != null && !criteria.getName().isEmpty()) {
      String fileName = new File(file.getFilePath()).getName();
      String searchName = criteria.getName();

      if (!criteria.isCaseSensitive()) {
        fileName = fileName.toLowerCase();
        searchName = searchName.toLowerCase();
      }

      if (criteria.isUseRegex()) {
        try {
          Pattern pattern = Pattern.compile(searchName);
          if (!pattern.matcher(fileName).find()) {
            return false;
          }
        } catch (Exception e) {
          return false;
        }
      } else {
        if (!fileName.contains(searchName)) {
          return false;
        }
      }
    }

    // 文件扩展名匹配
    if (criteria.getFileExtensions() != null && !criteria.getFileExtensions().isEmpty()) {
      String fileName = new File(file.getFilePath()).getName();
      final String extension;
      int lastDot = fileName.lastIndexOf('.');
      if (lastDot > 0) {
        extension = fileName.substring(lastDot + 1).toLowerCase();
      } else {
        extension = "";
      }

      boolean extensionMatch =
          criteria.getFileExtensions().stream()
              .anyMatch(ext -> ext.toLowerCase().equals(extension));
      if (!extensionMatch) {
        return false;
      }
    }

    // 文件大小匹配
    if (criteria.getMinSize() > 0 && file.getFileSize() < criteria.getMinSize()) {
      return false;
    }
    if (criteria.getMaxSize() > 0 && file.getFileSize() > criteria.getMaxSize()) {
      return false;
    }

    // 修改时间匹配
    LocalDateTime fileTime =
        LocalDateTime.ofInstant(
            java.time.Instant.ofEpochMilli(file.getLastModified()), ZoneId.systemDefault());

    if (criteria.getModifiedAfter() != null && fileTime.isBefore(criteria.getModifiedAfter())) {
      return false;
    }
    if (criteria.getModifiedBefore() != null && fileTime.isAfter(criteria.getModifiedBefore())) {
      return false;
    }

    return true;
  }

  /** 排序结果 */
  private List<FileMetadata> sortResults(List<FileMetadata> files, FileSearchCriteria criteria) {
    if (criteria.getSortBy() == null) {
      return files;
    }

    Comparator<FileMetadata> comparator;

    switch (criteria.getSortBy()) {
      case NAME:
        comparator = Comparator.comparing(f -> new File(f.getFilePath()).getName());
        break;
      case SIZE:
        comparator = Comparator.comparing(FileMetadata::getFileSize);
        break;
      case MODIFIED_TIME:
        comparator = Comparator.comparing(FileMetadata::getLastModified);
        break;
      case CREATED_TIME:
        comparator = Comparator.comparing(FileMetadata::getCreatedAt);
        break;
      case PATH:
        comparator = Comparator.comparing(FileMetadata::getFilePath);
        break;
      case EXTENSION:
        comparator =
            Comparator.comparing(
                f -> {
                  String fileName = new File(f.getFilePath()).getName();
                  int lastDot = fileName.lastIndexOf('.');
                  return lastDot > 0 ? fileName.substring(lastDot + 1) : "";
                });
        break;
      default:
        return files;
    }

    if (criteria.isSortDescending()) {
      comparator = comparator.reversed();
    }

    return files.stream().sorted(comparator).collect(Collectors.toList());
  }

  /** 创建文件元数据 */
  private FileMetadata createFileMetadata(Path file, BasicFileAttributes attrs) {
    FileMetadata metadata = new FileMetadata();
    metadata.setFilePath(file.toString());
    metadata.setFileSize(attrs.size());
    metadata.setLastModified(attrs.lastModifiedTime().toMillis());
    metadata.setCreatedAt(attrs.creationTime().toMillis());
    return metadata;
  }

  /** 计算文件哈希值 */
  private String calculateFileHash(FileMetadata file) {
    try {
      return com.summer.filesync.util.FileUtils.calculateSHA256(file.getFilePath());
    } catch (Exception e) {
      return "error_" + System.currentTimeMillis();
    }
  }

  /** 判断是否为文本文件 */
  private boolean isTextFile(Path file) {
    String fileName = file.getFileName().toString().toLowerCase();
    return fileName.endsWith(".txt")
        || fileName.endsWith(".log")
        || fileName.endsWith(".java")
        || fileName.endsWith(".xml")
        || fileName.endsWith(".json")
        || fileName.endsWith(".properties")
        || fileName.endsWith(".md")
        || fileName.endsWith(".html")
        || fileName.endsWith(".css")
        || fileName.endsWith(".js");
  }
}
